﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Stonecode.Solar.ParticleEngine.Emitters;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Stonecode.Solar.ParticleEngine.Collections
{
    /// <summary>
    /// A collection of Emitters. This is mainly used for more complex particle effects
    /// where multiple effects are needed
    /// </summary>
    public class EmitterCollection : List<Emitter>
    {
        private Vector3 pos;
        [ContentSerializerIgnore] 
        public Vector3 Position
        {
            get { return pos; }
            set
            {
                pos = value;
                for (int i = 0; i < this.Count; i++)
                {
                    this[i].Position = value;
                }
            }
        }
        public void Update(float dt)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].Update(dt);
            }
        }

        public void ClearParticles()
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].ClearParticles();
            }
        }

        public void Draw(GraphicsDevice graphics, float dt)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].Draw(graphics, dt);
            }
        }

        public void Draw(GraphicsDevice graphics, float dt, Matrix view, Matrix projection)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].ParticleSystem.SetCamera(view, projection);
                this[i].Draw(graphics, dt);
            }
        }

        public void SetAlive(bool val)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].IsAlive = val;
            }
        }

        public void Clone(GraphicsDevice graphics, Matrix view, Matrix proj, out EmitterCollection e)
        {
            
            e = new EmitterCollection();
            for (int i = 0; i < this.Count; i++)
            {
                switch (this[i].EmitterType)
                {
                    case EmitterType.Circle:
                        {
                            EmitterSettings es;
                            CircleEmitterTypeSettings cets = new CircleEmitterTypeSettings();
                            CircleEmitterTypeSettings current = ((CircleEmitter)this[i]).EmitterTypeSettings;
                            CopySettings(this[i].ParticleSystem.Settings, out es);
                            cets.RadiateOutward = current.RadiateOutward;
                            cets.Radius = current.Radius;
                            e.Add(new CircleEmitter(graphics, this[i].ParticleSystem.ParticleEffect.Clone(), es,
                                this[i].ParticleSystem.Texture, es.ParticlesPerSecond, Vector3.Zero, cets.Radius,
                                view, proj));
                            break;
                        }
                    case EmitterType.Line:
                        {
                            EmitterSettings es;
                            LineEmitterTypeSettings lets = new LineEmitterTypeSettings();
                            LineEmitterTypeSettings  current = ((LineEmitter)this[i]).EmitterTypeSettings;
                            CopySettings(this[i].ParticleSystem.Settings, out es);
                            lets.LineLength = current.LineLength;
                            lets.Rotation = current.Rotation;
                            e.Add(new LineEmitter(graphics, this[i].ParticleSystem.ParticleEffect.Clone(), es,
                                this[i].ParticleSystem.Texture, es.ParticlesPerSecond, Vector3.Zero, lets.LineLength,
                                lets.Rotation, view, proj));
                            break;
                        }
                    case EmitterType.Point:
                        {
                            EmitterSettings es;
                            PointEmitterTypeSettings pets = new PointEmitterTypeSettings();
                            PointEmitterTypeSettings current = ((PointEmitter)this[i]).EmitterTypeSettings;
                            pets.EllipticalVelocity = current.EllipticalVelocity;

                            CopySettings(this[i].ParticleSystem.Settings, out es);
                            e.Add(new PointEmitter(graphics, this[i].ParticleSystem.ParticleEffect.Clone(), es, pets,
                                this[i].ParticleSystem.Texture, es.ParticlesPerSecond, Vector3.Zero, view, proj));
                            break;
                        }
                    case EmitterType.Rectangle:
                        {
                            EmitterSettings es;
                            RectangleEmitterTypeSettings rets = ((RectangleEmitter)this[i]).EmitterTypeSettings;
                            CopySettings(this[i].ParticleSystem.Settings, out es);
                            e.Add(new RectangleEmitter(graphics, this[i].ParticleSystem.ParticleEffect.Clone(), es,
                                this[i].ParticleSystem.Texture, es.ParticlesPerSecond, rets.Rectangle, rets.Rotation,
                                view, proj));
                            break;
                        }
                }
                e[i].EmitterName = this[i].EmitterName;
                e[i].Enabled = this[i].Enabled;
            }
            e.Position = this.Position;
        }

        private void CopySettings(EmitterSettings s, out EmitterSettings es)
        {
            es = new EmitterSettings(s.MaxParticles);
            
            es.AlphaBlendFunction = s.AlphaBlendFunction;
            es.AlphaDestinationBlend = s.AlphaDestinationBlend;
            es.AlphaSourceBlend = s.AlphaSourceBlend;
            es.BlendFactor = s.BlendFactor;
            es.ColorBlendFunction = s.ColorBlendFunction;
            es.ColorDestinationBlend = s.ColorDestinationBlend;
            es.ColorSourceBlend = s.ColorSourceBlend;

            es.Duration = s.Duration;
            es.DurationRandomness = s.DurationRandomness;
            es.EmitterName = s.EmitterName;
            es.EmitterVelocitySensitivity = s.EmitterVelocitySensitivity;
            es.Enabled = s.Enabled;
            es.EndVelocity = s.EndVelocity;
            es.Gravity = s.Gravity;
            es.MaxColor = s.MaxColor;
            es.MaxEndSize = s.MaxEndSize;
            es.MaxHorizontalVelocity = s.MaxHorizontalVelocity;
            es.MaxRotateSpeed = s.MaxRotateSpeed;
            es.MaxStartSize = s.MaxStartSize;
            es.MaxVerticalVelocity = s.MaxVerticalVelocity;
            es.MinColor = s.MinColor;
            es.MinEndSize = s.MinEndSize;
            es.MinHorizontalVelocity = s.MinHorizontalVelocity;
            es.MinRotateSpeed = s.MinRotateSpeed;
            es.MinStartSize = s.MinStartSize;
            es.MinVerticalVelocity = s.MinVerticalVelocity;
            es.ParticlesPerSecond = s.ParticlesPerSecond;
            //es.SourceBlend = s.SourceBlend;
            es.TextureName = s.TextureName;
        }

        public void Trigger(float dt)
        {
            for (int i = 0; i < this.Count; i++)
            {
                switch (this[i].EmitterType)
                {
                    case EmitterType.Circle: ((CircleEmitter)this[i]).Trigger(dt); break;
                    case EmitterType.Line: ((LineEmitter)this[i]).Trigger(dt); break;
                    case EmitterType.Point: ((PointEmitter)this[i]).Trigger(dt); break;
                    case EmitterType.Rectangle: ((RectangleEmitter)this[i]).Trigger(dt); break; 
                }
            }
        }

        public void SetAutoGenerate(bool autoGenerate)
        {
            for (int i = 0; i < this.Count; i++)
                this[i].AutoGenerate = false;
        }

        public void SetGravity(Vector3 gravity)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].ParticleSystem.SetGravity(gravity);
            }
        }

        public void Dispose()
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].Dispose();
            }

            this.Clear();
        }

    }
}
